﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace System.Data.SugarClient.Soap.V2
{
	internal class V2LoginAction : V2Action
	{

		#region Constructors

		internal V2LoginAction(
			SugarSoapV2.sugarsoap service,
			string username,
			string password )
			: this(service, username, password, string.Empty, string.Empty)
		{
		}

		internal V2LoginAction(
			SugarSoapV2.sugarsoap service,
			string username,
			string password,
			string encryptionkey)
			: this(service, username, password, encryptionkey, string.Empty)
		{
		}

		internal V2LoginAction(
			SugarSoapV2.sugarsoap service,
			string username,
			string password,
			string encryptionkey,
			string applicationname
			)
			: base(service) 
		{
			this._username = username;
			this._password = password;
			if (!string.IsNullOrEmpty(encryptionkey)) this._encryptionkey = encryptionkey;
			if (!string.IsNullOrEmpty(applicationname)) this._applicationname = applicationname;
		}

		#endregion

		#region fields

		private readonly string _username;
		private readonly string _password;
		private readonly string _encryptionkey;
		private readonly string _applicationname = "SugarClient";

		#endregion

		#region Properties

		public string ApplicationName
		{
			get { return _applicationname; }
		}

		public string Encryptionkey
		{
			get { return _encryptionkey; }
		}

		public string Password
		{
			get { return _password; }
		}

		public string Username
		{
			get { return _username; }
		}

		#endregion

		protected override V2ActionResult ExecuteInner()
		{
			SugarSoapV2.user_auth auth = new SugarSoapV2.user_auth();
			auth.user_name = this.Username;
			auth.password = GetPasswordDigest();

			var result =
				this.SoapService.login(
					auth,
					this.ApplicationName,
					null);

			return new V2LoginActionResult(this, result);
		}

		protected string GetPasswordDigest()
		{
			return
				Hex((string.IsNullOrEmpty(this.Encryptionkey)) ? 
					MD5(this.Password) :
					TripleDES(this.Password, this.Encryptionkey));
		}

		private static byte[] MD5(string text)
		{
			return System.Security.Cryptography.MD5.Create().ComputeHash(Encoding.Default.GetBytes(text));
		}

		private static byte[] TripleDES(string password, string encryptionkey)
		{
			string userpass = password;

			using (TripleDES des = new TripleDESCryptoServiceProvider())
			{
				des.Mode = CipherMode.CBC;
				des.Key = Encoding.Default.GetBytes(Hex(MD5(encryptionkey)).Substring(0, 24));
				des.IV = Encoding.Default.GetBytes("password");
				des.Padding = PaddingMode.Zeros;

				return
					des.CreateEncryptor().TransformFinalBlock(
						Encoding.Default.GetBytes(userpass),
						0,
						Encoding.Default.GetByteCount(userpass)
						);
			}
		}

		private static string Hex(byte[] bytes)
		{
			StringBuilder s = new StringBuilder();
			foreach (byte b in bytes)
			{
				s.Append(b.ToString("X2", System.Globalization.CultureInfo.InvariantCulture));
			}
			return s.ToString();
		}

	}

	internal class V2LoginActionResult : V2ActionResult
	{

		internal V2LoginActionResult(
			V2LoginAction action,
			SugarSoapV2.entry_value result)
			: base(action)
		{
			this._result = result;
		}

		private readonly SugarSoapV2.entry_value _result;

		internal SugarSoapV2.entry_value RawResult
		{
			get { return _result; }
		}

		internal string SessionId
		{
			get { return this.RawResult.id; }
		}

		internal virtual bool Success
		{
			get
			{
				return true;
			}
		}

	}

}
